package npr;

import processing.core.*;
import processing.opengl.*;

import java.nio.*;
import javax.media.opengl.*;
import com.sun.opengl.util.*;


public class GLSL
{
    private int programObject;
    private static PApplet parent;
    private GL gl;
    private NPR renderer;
    private boolean vertexShaderEnabled;
    private boolean vertexShaderSupported; 
    private int vs;
    private int fs;
    
  
    public GLSL(){

	renderer= (NPR)parent.g;
	gl= renderer.gl;

	String extensions = gl.glGetString(GL.GL_EXTENSIONS);
	vertexShaderSupported = extensions.indexOf("GL_ARB_vertex_shader") != -1;
	vertexShaderEnabled = true;    
	programObject = gl.glCreateProgramObjectARB(); 
	vs=-1;
	fs=-1;
    }

    
    public static void setParent(PApplet applet){

	parent= applet;
    }

  
    public void loadVertexShader(String file){

	renderer= (NPR)parent.g;
	gl= renderer.gl;

	String glslFile[]= parent.loadStrings(file);
	String shaderSource=parent.join(glslFile,"\n");
	vs = gl.glCreateShaderObjectARB(GL.GL_VERTEX_SHADER_ARB);
	gl.glShaderSourceARB(vs, 1, new String[]{shaderSource},(int[]) null, 0);
	gl.glCompileShaderARB(vs);
	checkLogInfo(gl, vs);
	gl.glAttachObjectARB(programObject, vs); 
    }


    public void loadFragmentShader(String file){

	renderer= (NPR)parent.g;
	gl= renderer.gl;

	String glslFile[]= parent.loadStrings(file);
	String shaderSource=parent.join(glslFile,"\n");
	fs = gl.glCreateShaderObjectARB(GL.GL_FRAGMENT_SHADER_ARB);
	gl.glShaderSourceARB(fs, 1, new String[]{shaderSource},(int[]) null, 0);
	gl.glCompileShaderARB(fs);
	checkLogInfo(gl, fs);
	gl.glAttachObjectARB(programObject, fs); 
    }


    public int getAttribLocation(String name){
	
	renderer= (NPR)parent.g;
	gl= renderer.gl;

	return(gl.glGetAttribLocationARB(programObject,name));
    }
  

    public int getUniformLocation(String name){

	renderer= (NPR)parent.g;
	gl= renderer.gl;

	return(gl.glGetUniformLocationARB(programObject,name));

    }

    public void setTextureUnit(int location, int unit){
    
        renderer= (NPR)parent.g;
	gl= renderer.gl;

	gl.glUniform1iARB(location, unit);
    }


    public void setBoolean(int location, boolean value){
      
	renderer= (NPR)parent.g;
	gl= renderer.gl;

	if(value==true)
	    gl.glUniform1iARB(location, 1);
	else
	    gl.glUniform1iARB(location, 0);
    }


    public void setInteger(int location, int value){
      
	renderer= (NPR)parent.g;
	gl= renderer.gl;

	gl.glUniform1iARB(location, value);
    }


    public void setFloat(int location, float value){

	renderer= (NPR)parent.g;
	gl= renderer.gl;

	gl.glUniform1fARB(location, value);
    }

    public void setIntegerVec2(int location, int x, int y){
      
	renderer= (NPR)parent.g;
	gl= renderer.gl;

	gl.glUniform2iARB(location, x, y);
    }


    public void setFloatVec2(int location, float x, float y){

	renderer= (NPR)parent.g;
	gl= renderer.gl;

	gl.glUniform2fARB(location, x, y);
    }


    public void setIntegerVec3(int location, int x, int y, int z){

	renderer= (NPR)parent.g;
	gl= renderer.gl;      

	gl.glUniform3iARB(location, x, y, z);
    }


    public void setFloatVec3(int location, float x, float y, float z){

	renderer= (NPR)parent.g;
	gl= renderer.gl;

	gl.glUniform3fARB(location, x, y, z);
    }


    public void setIntegerVec4(int location, int x, int y, int z, int w){
      
	renderer= (NPR)parent.g;
	gl= renderer.gl;

	gl.glUniform4iARB(location, x, y, z, w);
    }


    public void setFloatVec4(int location, float x, float y, float z, float w){

	renderer= (NPR)parent.g;
	gl= renderer.gl;

	gl.glUniform4fARB(location, x, y, z, w);
    }


    public  void setMatrix3x3(int location, float[] data){
    
	renderer= (NPR)parent.g;
	gl= renderer.gl;

	gl.glUniformMatrix3fvARB(location, 1, false, data, 0);
    } 


    public void setMatrix4x4(int location, float[] data){
    
	renderer= (NPR)parent.g;
	gl= renderer.gl;

        gl.glUniformMatrix4fvARB(location, 1, false, data, 0);
    }    


    public void useShaders(){

	renderer= (NPR)parent.g;
	gl= renderer.gl;

	gl.glLinkProgramARB(programObject);
	gl.glValidateProgramARB(programObject);
	checkLogInfo(gl, programObject);
    }

  
    public void startShader(){

	renderer= (NPR)parent.g;
	gl= renderer.gl;

	gl.glUseProgramObjectARB(programObject); 
    }

  
    public void endShader(){

	renderer= (NPR)parent.g;
	gl= renderer.gl;

	gl.glUseProgramObjectARB(0); 
    }
  

    public void checkLogInfo(GL gl, int obj){

	renderer= (NPR)parent.g;
	gl= renderer.gl;

	IntBuffer iVal = BufferUtil.newIntBuffer(1);
	gl.glGetObjectParameterivARB(obj, GL.GL_OBJECT_INFO_LOG_LENGTH_ARB, iVal);
 
	int length = iVal.get();
	if (length <= 1)  
	    {
		return;
	    }
	ByteBuffer infoLog = BufferUtil.newByteBuffer(length);
	iVal.flip();
	gl.glGetInfoLogARB(obj, length, iVal, infoLog);
	byte[] infoBytes = new byte[length];
	infoLog.get(infoBytes);
	System.out.println("GLSL Validation >> " + new String(infoBytes));
    } 
}
